package com.treasure.mall.biz.service.core.product.impl;

import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.entity.product.CategoryPO;
import com.treasure.mall.biz.mapstruct.CategoryMapStrcut;
import com.treasure.mall.biz.repository.product.CategoryRepository;
import com.treasure.mall.biz.service.core.product.CategoryService;
import com.treasure.mall.biz.service.core.product.ProductService;
import com.treasure.mall.biz.service.core.user.MerchantService;
import com.treasure.mall.biz.vo.product.CategoryTreeVo;
import com.treasure.mall.biz.vo.product.CategoryVo;
import com.treasure.mall.zbq.common.SqlDataReader;
import com.treasure.mall.zbq.common.StringUtilsExt;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wm
 */
@Service("categoryService")
public class CategoryServiceImpl extends AbstractSearchableCrudService<CategoryPO, Long> implements CategoryService {
    @Autowired
    private CategoryRepository categoryRepository;
    @Autowired
    private ProductService productService;
    @Autowired
    private MerchantService merchantService;

    protected CategoryServiceImpl(CategoryRepository repository) {
        super(repository);
    }

    @Override
    protected SpecificationAndSort<CategoryPO> specificationAndSort(BaseSearchDTO searchDTO) {
        Specification<CategoryPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public CategoryPO save(BaseSaveDTO saveDTO) {
        return null;
    }

    @Override
    public List<CategoryPO> getListLevelTop2() {
        return categoryRepository.getListLevelTop2();
    }

    @Override
    public List<CategoryPO> getList(Long parentCatId) {
        return categoryRepository.getList(parentCatId);
    }

    @Override
    public ApiResult addOrUpdateCategory(CategoryPO categoryPO) {
        boolean isAdd = categoryPO.getCatId() == null || categoryPO.getCatId() <= 0;
        if (isAdd) {
            return addCategory(categoryPO);
        }
        return updateCategory(categoryPO);
    }

    @Override
    public CategoryPO getSingle(long catId) {
        return categoryRepository.findById(catId).orElse(null);
    }

    @Override
    public ApiResult delCategory(long catId) {
        CategoryPO po = this.getSingle(catId);
        if (po == null) {
            return ApiResult.errorWith(ResultCodeEnum.ERROR, "数据库中不存在");
        }
        List<CategoryPO> children = getList(catId);
        if (children.size() > 0) {
            return ApiResult.errorWith(ResultCodeEnum.ERROR, "存在下级，不允许删除");
        }

        if (productService.checkProductExistByCategoryId(catId)) {
            return ApiResult.errorWith(ResultCodeEnum.ERROR, "存在关联商品，不允许删除");
        }

        if (merchantService.checkExistByCategoryId(catId)) {
            return ApiResult.errorWith(ResultCodeEnum.ERROR, "存在关联商户，不允许删除");
        }

        repository.delete(po);
        return ApiResult.resultWith(ResultCodeEnum.SUCCESS);
    }

    @Override
    public CategoryTreeVo getApiTree() {
        List<CategoryPO> recommendList = categoryRepository.getRecommendList();
        List<CategoryPO> listTop2 = categoryRepository.getActiveListLevelTop2();
        List<CategoryPO> rootList = listTop2.stream().filter(x -> x.getDepth().equals(1)).collect(Collectors.toList());
        List<CategoryPO> subList = listTop2.stream().filter(x -> x.getDepth().equals(2)).collect(Collectors.toList());

        List<CategoryVo> rootVoList = CategoryMapStrcut.INSTANCE.po2vos(rootList);
        List<CategoryVo> subVoList = CategoryMapStrcut.INSTANCE.po2vos(subList);
        rootVoList.forEach(x -> {
            List<CategoryVo> vos = subVoList.stream().filter(m -> m.getParentCatId().equals(x.getCatId())).collect(Collectors.toList());
            x.setChildren(vos);
        });
        CategoryTreeVo vo = new CategoryTreeVo();
        vo.setRecommends(CategoryMapStrcut.INSTANCE.po2vos(recommendList));
        vo.setTree(rootVoList);
        return vo;
    }

    @Override
    public CategoryPO getRootCategory(Long catId) {
        CategoryPO current = categoryRepository.findById(catId).orElse(null);
        if (current == null) {
            return null;
        }
        String[] nodeList = StringUtilsExt.trim(current.getTreePath(), '|').split("\\|");
        if (StringUtils.isEmpty(nodeList[0])) {
            return null;
        }
        return categoryRepository.findById(new Long(nodeList[0])).orElse(null);
    }

    @Override
    public Map<Integer, String> getCategoryNames(List<Integer> catIdList) {
        if (catIdList == null || catIdList.size() == 0) {
            return new HashMap<>();
        }
        TreeSet set = new TreeSet(catIdList);
        catIdList.clear();
        catIdList.addAll(set);
        String s = "";
        for (Integer catId : catIdList) {
            s += catId.toString() + ",";
        }
        List<SqlDataReader> readerList = this.executeReaderList("select cat_id, cat_name from zb_category where cat_id in (" + StringUtilsExt.ltrim(s, ',') + ")");
        Map<Integer, String> map = new HashMap<>();
        readerList.forEach(reader -> {
            if (!map.containsKey(reader.getInteger("cat_id"))) {
                map.put(reader.getInteger("cat_id"), reader.getString("cat_name"));
            }
        });
        return map;
    }

    @Override
    public ApiResult addCategory(CategoryPO categoryPO) {
        if (categoryPO.getParentCatId() == null) {
            return ApiResult.errorWith(ResultCodeEnum.ERROR, "parentCatId未传");
        }
        Long parentCatId = 0L;
        CategoryPO parentCatPO = null;
        if (categoryPO.getParentCatId() > 0L) {
            parentCatPO = categoryRepository.findById(categoryPO.getParentCatId()).orElse(null);
            if (parentCatPO == null) {
                return ApiResult.errorWith(ResultCodeEnum.ERROR, "上级节点不存在");
            }
            parentCatId = parentCatPO.getCatId();
        }
        categoryPO.setCreateTime(LocalDateTime.now());
        categoryPO.setSortNo(50);
        categoryPO.setParentCatId(parentCatId);
        categoryPO = categoryRepository.saveAndFlush(categoryPO);
        categoryPO.setTreePath(parentCatPO == null ? String.format("|%s|", categoryPO.getCatId().toString()) : String.format("%s%s|", parentCatPO.getTreePath(), categoryPO.getCatId().toString()));
        categoryPO.setDepth(StringUtilsExt.trim(categoryPO.getTreePath(), '|').split("\\|").length);
        categoryPO = categoryRepository.save(categoryPO);
        return ApiResult.resultWith(ResultCodeEnum.SUCCESS, categoryPO);
    }

    private ApiResult updateCategory(CategoryPO categoryPO) {
        CategoryPO model = categoryRepository.findById(categoryPO.getCatId()).orElse(null);
        if (model == null) {
            return ApiResult.errorWith(ResultCodeEnum.ERROR, "数据库中不存在");
        }
        model.setCatName(categoryPO.getCatName());
        model.setRebateRateOne(categoryPO.getRebateRateOne());
        model.setRebateRateTwo(categoryPO.getRebateRateTwo());
        model.setCommissionRate(categoryPO.getCommissionRate());
        model.setSortNo(categoryPO.getSortNo());
        model.setUpdateTime(LocalDateTime.now());
        model.setCatPic(categoryPO.getCatPic());
        model.setRecommendFlag(categoryPO.getRecommendFlag());
        model.setRemark(categoryPO.getRemark());
        model.setStatusCode(categoryPO.getStatusCode());
        categoryRepository.saveAndFlush(model);
        return ApiResult.resultWith(ResultCodeEnum.SUCCESS);
    }
}